﻿//PlazaRouter.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Plaza
{
	using System;
	using System.IO;
	using System.Linq;
	using System.ServiceProcess;
	using System.Diagnostics;
	using System.Threading;

	using Ecng.Common;

	using Microsoft.Win32;

	/// <summary>
	/// Класс для управляения и настройки программы P2MQRouter.exe, которая осуществляет подключение к Plaza 2.
	/// </summary>
	public class PlazaRouter
	{
		private readonly PlazaConnectionPool _connectionPool;
		private readonly ServiceController _serviceController;

		private const string _serviceName = "FORTSGATE_Router";
		private const string _exeName = "P2MQRouter.exe";
		private const string _configFileName = "client_router.ini";

		internal PlazaRouter(PlazaConnectionPool connectionPool)
		{
			if (connectionPool == null)
				throw new ArgumentNullException("connectionPool");

			_connectionPool = connectionPool;

			try
			{
				var addr = _connectionPool.Address.ToString();
				_serviceController = ServiceController
					.GetServices(addr.Substring(0, addr.IndexOf(':')))
					.FirstOrDefault(c => c.ServiceName == _serviceName);
			}
			catch (Exception e)
			{
				Trace.WriteLine(e);
			}

			if (_serviceController == null)
			{
				IsServiceController = false;
				ExecutableFileName = Path.Combine(Path.Combine(InstallDirName, "p2bin"), _exeName);
				ConfigFilePath = Path.Combine(InstallDirName, _configFileName);
			}
			else
			{
				IsServiceController = true;

				const string regPath = @"System\CurrentControlSet\Services\" + _serviceName;

				var rk = Registry.LocalMachine.OpenSubKey(regPath);

				if (rk == null)
					throw new InvalidOperationException("Путь в реестре {0} отсутствует.".Put(regPath));

				var servicePath = (string)rk.GetValue("ImagePath");

				ExecutableFileName = servicePath.Substring(0, servicePath.IndexOf(".exe") + 4);

				if (ExecutableFileName.IsEmpty())
					throw new InvalidOperationException("Путь {0} не содержит название файла.".Put(servicePath));

				var buffer = servicePath.Substring(ExecutableFileName.Length + 1);
				var args = buffer.Split(new[] { "\"" }, StringSplitOptions.RemoveEmptyEntries).Where(x => x.StartsWith("/"));

				foreach (var item in args)
				{
					if (item.ToLowerInvariant().StartsWith("/ini:"))
					{
						ConfigFilePath = item.Substring(5);
						break;
					}
				}
			}

			ConfigParser = new PlazaRouterConfigParser(ConfigFilePath);
		}

		/// <summary>
		/// Возвращает объект Process для запущенного роутера.
		/// Если роутер запущен, как сервис Windows, вызывает InvalidOperationException.
		/// </summary>
		/// <returns>Процесс запущенного роутера.</returns>
		public static Process GetConsoleProcess()
		{
			if (IsServiceController)
				throw new InvalidOperationException("Роутер установлен как сервис Windows");

			return Process.GetProcessesByName(Path.GetFileNameWithoutExtension(_exeName)).FirstOrDefault();
		}

		/// <summary>
		/// true - программа запускается, как сервис Windows,
		/// false - программа запускается вручную.
		/// </summary>
		public static bool IsServiceController
		{
			get;
			private set;
		}

		/// <summary>
		/// Парсер конфига.
		/// </summary>
		public PlazaRouterConfigParser ConfigParser { get; private set; }

		/// <summary>
		/// Текущий статус роутера.
		/// </summary>
		public ServiceControllerStatus Status
		{
			get 
			{
				if (IsServiceController)
				{
					_serviceController.Refresh();
					return _serviceController.Status;
				}
				else
				{
					return GetConsoleProcess() != null ? ServiceControllerStatus.Running : ServiceControllerStatus.Stopped;
				}
			}
		}

		/// <summary>
		/// Директория, в которую устанавливается программа P2MQRouter.exe.
		/// </summary>
		public string InstallDirName
		{
			get
			{
				return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"P2FORTSGate\");
			}
		}

		/// <summary>
		/// Путь к исполняемому файлу P2MQRouter.exe.
		/// </summary>
		public string ExecutableFileName
		{
			get;
			private set;
		}

		/// <summary>
		/// Путь к конфиг-файлу client_router.ini.
		/// </summary>
		public string ConfigFilePath
		{
			get;
			private set;
		}

		/// <summary>
		/// Запускает роутер
		/// </summary>
		public void Start()
		{
			if (Status == ServiceControllerStatus.Running || Status == ServiceControllerStatus.StartPending)
				return;

			if (IsServiceController)
			{
				_serviceController.Start();

				Trace.WriteLine("Service has been started");
			}
			else
			{
				var psi = new ProcessStartInfo
				{
					FileName = ExecutableFileName,
					WorkingDirectory = InstallDirName,
					Arguments = "/ini:{0}".Put(_configFileName),
					UseShellExecute = false
				};
				Process.Start(psi);
			}
		}

		/// <summary>
		/// Выгружает запущенный роутер
		/// </summary>
		public void Stop()
		{
			if (Status == ServiceControllerStatus.Stopped || Status == ServiceControllerStatus.StopPending)
				return;

			if (IsServiceController)
			{
				_serviceController.Stop();

				Trace.WriteLine("Service has been stopped");
			}
			else
			{
				var p = GetConsoleProcess();

				if (p != null)
				{
					p.Kill();

					foreach (var item in Process.GetProcessesByName("p2replinter"))
					{
						item.Kill();
					}

					foreach (var item in Process.GetProcessesByName("P2FORTSCommonVolat"))
					{
						item.Kill();
					}
				}
			}
		}

		/// <summary>
		/// Перезапускает роутер
		/// </summary>
		public void Restart()
		{
			Stop();

			if (IsServiceController)
			{
				while (Status != ServiceControllerStatus.Stopped)
				{
					Thread.Sleep(200);
				}
			}
			else
			{
                var p = GetConsoleProcess();
                if (p != null && !p.WaitForExit(3000))
                    throw new Exception("Не удалось остановить процесс роутера");
			}

			Start();
		}
	}
}